#include "zrpc/net/channel.h"

#include "zrpc/net/event_loop.h"

namespace zrpc {
const int Channel::kNoneEvent = 0;
const int Channel::kReadEvent = POLLIN | POLLPRI;
const int Channel::kWriteEvent = POLLOUT;

Channel::Channel(EventLoop* loop, int32_t fd)
    : loop_(loop),
      fd_(fd),
      events_(0),
      revents_(0),
      index_(-1),
      tied_(false),
      event_handling_(false),
      added_to_loop_(false) {}

Channel::~Channel() {
  assert(!event_handling_);
  assert(!added_to_loop_);

  if (loop_->IsInLoopThread()) {
    assert(!loop_->HasChannel(this));
  }
}

void Channel::Remove() {
  assert(IsNoneEvent());
  added_to_loop_ = false;
  loop_->RemoveChannel(this);
}

void Channel::Update() {
  added_to_loop_ = true;
  loop_->UpdateChannel(this);
}

void Channel::HandleEventWithGuard() {
  event_handling_ = true;

  if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) {
    if (log_hup_) {
    }

    if (close_callback_) {
      close_callback_();
    }
  }

  if (revents_ & POLLNVAL) {
  }

  if (revents_ & (POLLERR | POLLNVAL)) {
    if (error_callback_) {
      error_callback_();
    }
  }

  #ifndef POLLRDHUP
   const int POLLRDHUP = 0;
  #endif

  if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) {
    if (read_callback_) {
      read_callback_();
    }
  }

  if (revents_ & POLLOUT) {
    if (write_callback_) {
      write_callback_();
    }
  }
  event_handling_ = false;
}

void Channel::HandleEvent() {
  std::shared_ptr<void> guard;
  if (tied_) {
    guard = tie_.lock();
    if (guard) {
      HandleEventWithGuard();
    }
  } else {
    HandleEventWithGuard();
  }
}

void Channel::SetTie(const std::shared_ptr<void>& obj) {
  tie_ = obj;
  tied_ = true;
}
}  // namespace zrpc
